package dal

import (
	"context"
	"errors"

	v1 "code.byted.org/bytertc/whiteboard_server/biz/api/pb/v1"
	"code.byted.org/bytertc/whiteboard_server/biz/dal/ddl"
	"code.byted.org/bytertc/whiteboard_server/biz/dal/spec"
	"code.byted.org/bytertc/whiteboard_server/biz/service/action"
	"code.byted.org/bytertc/whiteboard_server/biz/service/action/draw/phase"
	"code.byted.org/bytertc/whiteboard_server/biz/service/object"
	"code.byted.org/kv/redis-v6"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
)

type Repo interface {
	CreateElement(ctx context.Context, element object.Element) error
	SaveElement(ctx context.Context, element object.Element) error
	GetElement(ctx context.Context, unique spec.ObjectUnique) (object.Element, error)
	GetElements(ctx context.Context, unique spec.PageUnique, ids []string) ([]object.Element, error)
	ListElementIds(ctx context.Context, unique spec.PageUnique) ([]string, error) // not including NotFound error
	DeleteElement(ctx context.Context, unique spec.PageObjectUnique) error

	GetPhases(ctx context.Context, action spec.ActionUnique) ([]phase.Phase, error)
	SavePhases(ctx context.Context, phases []phase.Phase) error
	SavePacket(ctx context.Context, unique spec.BoardUnique, packet *v1.Packet) (pk int64, total int64, err error)
	GetPackets(ctx context.Context, unique spec.RoomUnique, maxId int64) ([]*ddl.Packet, error)
	GetMaxPacketId(ctx context.Context, unique spec.RoomUnique) (int64, error)
	SaveReplay(ctx context.Context, replay *ddl.Replay) error
	ListReplay(ctx context.Context, unique spec.BoardUnique) ([]ddl.Replay, error)
	IncrTransformCount(ctx context.Context, unique spec.ActionUnique, operator string) (int64, error)
	ChangeCursorState(ctx context.Context, unique spec.BoardUnique, operator string, state *v1.ChangeCursorState) error
	GetTopNCursorState(ctx context.Context, unique spec.BoardUnique) (map[string]*v1.UserCursorInfo, error)
	GetMyCursorState(ctx context.Context, unique spec.BoardUnique, operator string) (*v1.ChangeCursorState, error)

	GetPages(ctx context.Context, unique spec.BoardUnique, pageIds []string) ([]*object.Page, error)
	GetPageCount(ctx context.Context, unique spec.BoardUnique) (int32, error)
	GetExtraCategory(ctx context.Context, unique spec.BoardUnique) ([]string, error)
	// GetBoards not including NotFound error
	GetBoards(ctx context.Context, unique spec.RoomUnique, boardIds []int32) ([]*v1.BoardInfo, error)
	GetFirstBoardId(ctx context.Context, unique spec.RoomUnique) (int32, error)
	// CreateBoard creates board and initial page both uniquely
	CreateBoard(ctx context.Context, unique spec.BoardUnique, initBoard *v1.BoardInfo, initialPages []*v1.PageInfo) error
	CloseBoard(ctx context.Context, unique spec.RoomUnique, boardId int32) (ok bool, err error)
	CloseBoards(ctx context.Context, unique spec.RoomUnique) (err error)
	FlipPage(ctx context.Context, unique spec.BoardUnique, currentPage string) error
	UpdateBoard(ctx context.Context, unique spec.BoardUnique, oldCount, addition int32, info *v1.BoardInfo) error
	ZoomBoard(ctx context.Context, unique spec.BoardUnique, info *v1.ZoomInfo) error
	StepChange(ctx context.Context, unique spec.BoardUnique, info *v1.PptStepChange) error
	PptMediaChange(ctx context.Context, unique spec.BoardUnique, change *v1.PptMediaChange) error
	PptTriggerChange(ctx context.Context, unique spec.BoardUnique, change *v1.PptTriggerChange) error
	GetZoomInfo(ctx context.Context, unique spec.BoardUnique) (*v1.ZoomInfo, error)
	GetPptMediaInfo(ctx context.Context, unique spec.BoardUnique, pageID string) ([]*v1.PptMediaInfo, error)
	GetPptTriggerInfo(ctx context.Context, unique spec.BoardUnique, pageID string) ([]*v1.PptTriggerInfo, error)
	// CreatePages returns biz_error.Conflict
	CreatePages(ctx context.Context, unique spec.BoardUnique, infos []*v1.PageInfo, prePageId string) (int64, error)
	UpdatePage(ctx context.Context, unique spec.PageUnique, oldCount, addition int32, info *v1.PageInfo) error
	DeletePages(ctx context.Context, unique spec.BoardUnique, pageIds []string, isContinuous bool) error
	LockPageAudio(ctx context.Context, unique spec.PageUnique, objID string) error
	UnLockPageAudio(ctx context.Context, unique spec.PageUnique) error
	LockPageVideo(ctx context.Context, unique spec.PageUnique, objID string) error
	UnLockPageVideo(ctx context.Context, unique spec.PageUnique) error
	LockObject(ctx context.Context, action action.Action) error
	UnlockObject(ctx context.Context, action action.Action) error
	GetLockedObjects(ctx context.Context, unique spec.BoardUnique) (map[string]string, error)
	GetActionCount(ctx context.Context, unique spec.PageUnique) (map[string]int32, error)
	GetPageActionCount(ctx context.Context, unique spec.PageUnique) (int32, error)
	GetPageControlCount(ctx context.Context, unique spec.PageUnique) (int32, error)
	GetBoardControlCount(ctx context.Context, unique spec.BoardUnique) (int32, error)

	UpdatePacketId(ctx context.Context, unique spec.OperatorUnique, currentPacketId int32) error
	GetPacketId(ctx context.Context, unique spec.OperatorUnique) (int32, error)
	Authenticate(ctx context.Context, action action.Action) error
	SetHeartbeatStamp(ctx context.Context, unique spec.RoomUnique) (bool, error)

	SetEnterTimeStamp(ctx context.Context, unique spec.OperatorUnique, timestamp int64) error
	GetEnterTimeStamp(ctx context.Context, unique spec.OperatorUnique) (int64, error)
	GetEnterSetSize(ctx context.Context, unique spec.OperatorUnique) (int64, error)
	DelEnterTimeStamp(ctx context.Context, unique spec.OperatorUnique) error
	DelHeartbeatTimeStamp(ctx context.Context, unique spec.OperatorUnique) error
	UpdateHeartbeatTimeStamp(ctx context.Context, unique spec.OperatorUnique, timestamp int64) error
	GetHeartbeatTimeStamp(ctx context.Context, unique spec.OperatorUnique) (int64, error)
	GetHeartbeatTimeStamps(ctx context.Context, unique spec.RoomUnique, deadline int64) (map[string]int64, error)
	UpdateRoomSet(ctx context.Context, unique spec.RoomUnique) error
	SetRoomSet(ctx context.Context, unique spec.RoomUnique) error
	DelRoom(ctx context.Context, unique spec.RoomUnique) error
	GetTopNRooms(ctx context.Context, top int64) ([]string, error)
	SetFirstHbTimeStamp(ctx context.Context, unique spec.OperatorUnique, timestamp int64) error

	GetConfigs(ctx context.Context, appId string, parentCategory int) ([]ddl.ConsoleConfig, error)
	SetConfig(ctx context.Context, unique spec.ConsoleItemUnique) error
	GetConfig(ctx context.Context, unique spec.ConsoleBaseUnique, all bool) ([]ddl.ConsoleConfig, error)
	UpdateConfig(ctx context.Context, unique spec.ConsoleItemUnique) error
	DeleteConfig(ctx context.Context, unique spec.ConsoleBaseUnique) error
	GetSwitchFromCache(ctx context.Context, unique spec.ConsoleSwitchUnique) (int, error)

	GetSwitchInfos(ctx context.Context, unique spec.ConsoleBaseUnique) ([]ddl.ConsoleSwitch, error)
	GetSwitchInfo(ctx context.Context, unique spec.ConsoleBaseUnique) ([]ddl.ConsoleSwitch, error)
	UpdateSwitchInfo(ctx context.Context, unique spec.ConsoleSwitchUnique) error
	CreateSwitchInfo(ctx context.Context, unique spec.ConsoleSwitchUnique) error

	CreateTranscodeTask(ctx context.Context, task *ddl.TranscodeTask) error
	GetTranscodeTask(ctx context.Context, unique spec.TranscodeTaskUnique) (*ddl.TranscodeTask, error)
	GetTranscodeTaskByFileID(ctx context.Context, fileID string) (*ddl.TranscodeTask, error)
	UpdateTranscodeTask(ctx context.Context, unique spec.TranscodeTaskUnique, ups map[string]interface{}) error
	GetExceptionStaticTask(ctx context.Context) ([]*ddl.TranscodeTask, error)
	GetExceptionDynamicTask(ctx context.Context) ([]*ddl.TranscodeTask, error)
	UpdateExceptionStaticTask(ctx context.Context, taskIDs []string) error
	UpdateExceptionDynamicTask(ctx context.Context, taskIDs []string) error
	BatchCreateTranscodeResult(ctx context.Context, results []*ddl.TranscodeResult) error
	GetTranscodeResult(ctx context.Context, unique spec.TranscodeTaskUnique) ([]*ddl.TranscodeResult, error)
	LockStaticMonitor(ctx context.Context) error
	LockDynamicMonitor(ctx context.Context) error
	LockTranscodeTask(ctx context.Context, taskID string) error

	//rooms
	GetRoom(ctx context.Context, unique spec.RoomUnique) (*ddl.Rooms, error)
	CreateRoom(ctx context.Context, unique spec.BoardUnique) error
	UpdateActiveBoardId(ctx context.Context, unique spec.RoomUnique, activeBoardId int32) error
	RoomExist(ctx context.Context, unique spec.BoardUnique) (bool, error)
	CloseRoom(ctx context.Context, unique spec.RoomUnique) error

	GetWsParam(ctx context.Context, appID, roomID string) (*ddl.WsParam, error)
}

func IsDuplicateError(err error) bool {
	mysqlErr := &mysql.MySQLError{}
	return errors.As(err, &mysqlErr) && mysqlErr.Number == 1062
}

func IsNotFoundError(err error) bool {
	return errors.Is(err, gorm.ErrRecordNotFound) || errors.Is(err, redis.Nil)
}
